#!/bin/bash
# File Name: xtrabackup.sh
# Author: moshan
# mail: mo_shan@yeah.net
# Created Time: 2019-05-24 14:03:23
# Function: 基于lbzip2压缩及xtrabackup流备份的自动恢复脚本
#########################################################################
mysql_conf="${1}"
backup_dir="${2}"
copy_type="${3}"
if [ "${copy_type}x" == "movex" ]
then
	copy_type="--move-back"
else
	copy_type="--copy-back"
fi
localhost_ip=($(ip a 2>/dev/null|grep inet|grep brd|grep scope|awk '{print $2}'|awk -F'/' '{print $1}'))
[ "${localhost_ip}x" == "x" ] && localhost_ip="$(hostname)"
log_file="/tmp/xtrabackup.log"
[ ! -f "${log_file}" ] && touch ${log_file}

function f_logging()
{
	log_mode="${1}"
	log_info="${2}"
	log_enter="${3}"
	enter_opt=""
	if [ "${log_mode}x" == "WARNx" ]
	then
		#WARN级别是黄色显示
		echo -e "\033[33m"
	elif [ "${log_mode}x" == "ERRORx" ]
	then
		#ERROR级别是红色显示
		echo -e "\033[31m"
	elif [ "${log_mode}x" == "COMMANDx" ]
	then
		#COMMAND级别是蓝色显示
		echo -en "\033[34m"
	else
		#INFO级别是绿色显示
		echo -en "\033[32m"
	fi
	if [ "${log_enter}x" == "0x" ]
	then
		log_enter="-n"
	elif [ "${log_enter}x" == "2x" ]
	then
		log_enter="-e"
		enter_opt="\n"
	else
		log_enter="-e"
	fi
	echo ${log_enter} "[$(date "+%F %H:%M:%S")] [${log_mode}] [${localhost_ip}] ${log_info}${enter_opt}"
	echo -en "\033[0m"
	echo -en "\033[32m"
}


f_logging "WARN" "开始 >> 恢复流程正在开始......" "2"|tee -a ${log_file}
if [ ! -f "${mysql_conf}" ]
then
	f_logging "ERROR" "提示 >> MySQL配置文件不存在, 程序执行结束!" "2"|tee -a ${log_file}
	exit
fi
mysql_port="$(tr -d " \t" < ${mysql_conf}|grep -i "^port=.*[0-9]$"|tail -1|awk -F= '{print $2}')"
mysql_data_dir="$(tr -d " \t" < ${mysql_conf}|grep -i "^datadir="|awk -F= '{print $2}')"
if [ "$(grep -c "/$" <<< "${mysql_data_dir}")x" == "1x" ]
then
	mysql_tmp_dir="$(awk -F'/' 'OFS="/",NF-=2' <<< "${mysql_data_dir}")/tmp"
else
	mysql_tmp_dir="$(awk -F'/' 'OFS="/",NF-=1' <<< "${mysql_data_dir}")/tmp"
fi

full_backup_file="$(ls ${backup_dir}/${mysql_port}_full_stream_${mysql_port}*.bz2)"
if [ ! -f "${full_backup_file}" ]
then
	f_logging "ERROR" "提示 >> MySQL全备备份文件不存在, 程序执行结束!" "2"|tee -a ${log_file}
	exit
fi
#full_backup_file="$(ls ${backup_dir}/${mysql_port}_full_stream_${mysql_port}*.bz2)"
incremental_backup_file_array=($(ls ${backup_dir}/${mysql_port}_incremental_stream_${mysql_port}*.bz2 2>/dev/null))
tmp1="${mysql_tmp_dir}/tmp1"
tmp2="${mysql_tmp_dir}/tmp2"
tmp3="${mysql_tmp_dir}/tmp3"


mkdir -p ${mysql_tmp_dir}/{tmp1,tmp2,tmp3}

backup_file_array=(${full_backup_file} ${incremental_backup_file_array[@]})

if [ "$(which lbzip2 2>/dev/null)x" == "x" ]
then
	f_logging "ERROR" "提示 >> 该系统没有lbzip2解压工具, 请手动安装, 程序执行结束!" "2"|tee -a ${log_file}
	exit
elif [ "$(which xbstream 2>/dev/null)x" == "x" ]
then
	f_logging "ERROR" "提示 >> 该系统没有xtrabackup环境, 请手动安装, 程序执行结束!" "2"|tee -a ${log_file}
	exit
elif [ -d "${tmp1}" ]
then
	f_logging "WARN" "提示 >> ${tmp1}数据目录不为空, 请手动清空后再重新运行脚本!" "2"|tee -a ${log_file}
	exit
elif [ -d "${mysql_data_dir}" ]
then
	if [ "$(ls ${mysql_data_dir}|wc -l)x" != "0x" ]
	then
		mysql_data_dir_stat=1
		f_logging "WARN" "提示 >> MySQL数据目录不为空, 请选择是否继续向下执行!" "2"|tee -a ${log_file}
		read -p "请输入您的选择[y|n|Y|N]:" choose
		[ "$(grep -ic "y" <<< "${choose}")x" == "0x" ] && exit
	fi
fi

f_logging "INFO" "解压 >> 正在解压MySQL备份文件, 请稍等......"|tee -a ${log_file}
tmp_file1=".decom_count_mark"
tmp_file2=".decom_count"
echo 0 > ${tmp_file1}
echo 0 > ${tmp_file2}
for file in ${backup_file_array[@]}
do
	{
		f_logging "INFO" "解压 >> 正在解压${file}, 请稍等......"|tee -a ${log_file}
		lbzip2 -d -k ${file}
		if [ $? -eq 0 ]
		then
			while :
			do
				if [ "$(lsattr ${tmp_file1}|grep -c -- "----i")x" == "0x" ]
				then
					chattr +i ${tmp_file1}
					tmp="$(($(cat ${tmp_file2})+1))"
					echo ${tmp} > ${tmp_file2}
					if [ "$(cat ${tmp_file2})x" == "${tmp}x" ]
					then
						chattr -i ${tmp_file1}
					fi
					break
				else
					sleep 1
				fi
			done
			f_logging "INFO" "解压 >> ${file}解压完成!"|tee -a ${log_file}
		else
			f_logging "ERROR" "解压 >> ${file}解压失败!" "2"|tee -a ${log_file}
		fi
	} &
done
wait

decom_count="$(cat ${tmp_file2})"
[ -f "${tmp_file2}" ] && rm -f ${tmp_file2}
[ -f "${tmp_file1}" ] && rm -f ${tmp_file1}

if [ "${decom_count}x" == "${#backup_file_array[@]}x" ]
then
	f_logging "INFO" "解压 >> MySQL备份文件解压完成!"|tee -a ${log_file}
else
	f_logging "ERROR" "解压 >> 部分或者全部MySQL备份文件解压失败, 程序执行结束!" "2"|tee -a ${log_file}
	exit
fi

full_backup_file="$(ls ${backup_dir}/${mysql_port}_full_stream_${mysql_port}*|grep -v ".bz2$")"
incremental_backup_file_array=($(ls ${backup_dir}/${mysql_port}_incremental_stream_${mysql_port}* 2>/dev/null|grep -v "bz2$"))

f_logging "INFO" "抽取 >> 正在流抽取全备文件[${full_backup_file}], 请稍等......"|tee -a ${log_file}
xbstream -x < ${full_backup_file} -C ${tmp1}
if [ $? -eq 0 ]
then
	f_logging "INFO" "抽取 >> 流抽取全备文件[${full_backup_file}]完成!"|tee -a ${log_file}
else
	f_logging "ERROR" "抽取 >> 流抽取全备文件[${full_backup_file}]失败, 程序执行结束!" "2"|tee -a ${log_file}
	exit
fi

f_logging "INFO" "应用 >> 正在应用全备文件[${full_backup_file}]的redo log, 请稍等......"|tee -a ${log_file}
if [ "${#incremental_backup_file_array[@]}x" == "0x" ]
then
	redo_only=""
else
	redo_only="--redo-only"
fi
innobackupex --prepare ${redo_only} --apply-log --tmpdir=${tmp3} ${tmp1}
if [ $? -eq 0 ]
then
	f_logging "INFO" "应用 >> 全备文件[${full_backup_file}]redo log应用完成!"|tee -a ${log_file}
else
	f_logging "ERROR" "应用 >> 全备文件[${full_backup_file}]redo log应用失败, 程序执行结束!" "2"|tee -a ${log_file}
	exit
fi
for ((i=0;i<${#incremental_backup_file_array[@]};i++))
do
	[ -d "${tmp2}" ] && rm -rf ${tmp2}/* || mkidr -p ${tmp2}
	f_logging "INFO" "抽取 >> 正在流抽取第$((${i}+1))个增量备份文件[${incremental_backup_file_array[${i}]}], 请稍等......"|tee -a ${log_file}
	xbstream -x < ${incremental_backup_file_array[${i}]} -C ${tmp2}
	if [ $? -eq 0 ]
	then
		f_logging "INFO" "抽取 >> 流抽取第$((${i}+1))个增量备份文件[${incremental_backup_file_array[${i}]}]完成!"|tee -a ${log_file}
	else
		f_logging "ERROR" "抽取 >> 流抽取第$((${i}+1))个增量备份文件[${incremental_backup_file_array[${i}]}]失败, 程序执行结束！" "2"|tee -a ${log_file}
		exit
	fi
	[ "$((${i}+1))x" == "${#incremental_backup_file_array[@]}x" ] && redo_only=""
	f_logging "INFO" "应用 >> 正在应用第$((${i}+1))个增量备份文件[${incremental_backup_file_array[${i}]}]的redo log, 并合并到全量备份目录, 请稍等......!"|tee -a ${log_file}
	innobackupex --prepare ${redo_only} --apply-log --incremental-dir=${tmp2} --tmpdir=${tmp3} ${tmp1}
	if [ $? -eq 0 ]
	then
		f_logging "INFO" "应用 >> 第$((${i}+1))个增量备份文件[${incremental_backup_file_array[${i}]}]redo log应用完成, 合并到全量备份目录完成!"|tee -a ${log_file}
	else
		f_logging "ERROR" "应用 >> 第$((${i}+1))个增量备份文件[${incremental_backup_file_array[${i}]}]redo log应用失败, 合并到全量备份目录失败, 程序执行结束!" "2"|tee -a ${log_file}
		exit
	fi
done

f_logging "INFO" "拷贝 >> >> 正在拷贝相关文件到MySQL数据目录[copy ${tmp1} to ${mysql_data_dir}], 请稍等......"|tee -a ${log_file}
if [ "${mysql_data_dir_stat}x" == "1x" ]
then
	f_logging "WARN" "拷贝 >> 因为MySQL的数据目录非空, 请用户手动处理, 程序执行结束!"|tee -a ${log_file}
	exit
else
	innobackupex --defaults-file=${mysql_conf} ${copy_type} --use-memory=500M --tmpdir=${tmp3} ${tmp1}
	if [ $? -eq 0 ]
	then
		f_logging "INFO" "拷贝 >> 文件拷贝完成!"|tee -a ${log_file}
		f_logging "WARN" "完成 >> 恢复完成, 启动MySQL进程前, 请检查MySQL数据目录的权限!"|tee -a ${log_file}
	else
		f_logging "ERROR" "拷贝 >> 文件拷贝失败, 程序执行结束!" "2"|tee -a ${log_file}
		f_logging "WARN" "完成 >> 恢复失败!"|tee -a ${log_file}
		exit
	fi
fi
